package com.zenchn.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zenchn.annotation.OperLog;
import com.zenchn.entity.*;
import com.zenchn.enums.CommonStatusEnum;
import com.zenchn.enums.DictTypeEnum;
import com.zenchn.enums.OperLogActionEnum;
import com.zenchn.enums.SessionAttributeEnum;
import com.zenchn.exception.CheckException;
import com.zenchn.model.*;
import com.zenchn.service.*;
import com.zenchn.utils.AuthUtils;
import com.zenchn.utils.CommonUtils;
import com.zenchn.utils.PwdHashSaltUtils;
import io.swagger.annotations.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 账户管理控制器
 *
 * @author panbingqi
 * @date 2021-06-01
 */
@RestController
@RequestMapping(value = "account")
@Api(value = "账户管理模块相关接口", tags = "用户管理-账户管理")
@RequiresPermissions("account:manage")
public class AccountController {
    private final String MODULE = "用户管理>账户管理";

    @Resource
    private RoleService roleService;

    @Resource
    private RoleAuthorityMapperService roleAuthorityMapperService;


    @Resource
    private AccountService accountService;

    @Resource
    private AccountRoleMapperService accountRoleMapperService;

    @Resource
    private DictService dictService;

    @Resource
    private AccountExtendService accountExtendService;

    @Resource
    private AreasService areasService;

    @Resource
    private RegionService regionService;


    /**
     * 分页获取账户列表
     *
     * @param keyword
     * @param status
     * @param page
     * @param pageSize
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "分页获取账户列表")
    @ApiOperation(value = "分页获取账户列表", notes = "分页获取账户列表")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "String", name = "keyword", value = "关键字"),
            @ApiImplicitParam(dataType = "Integer", name = "status", value = "状态"),
            @ApiImplicitParam(dataType = "Integer", name = "page", value = "当前第page页"),
            @ApiImplicitParam(dataType = "Integer", name = "pageSize", value = "每页pageSize数量")
    })
    @GetMapping(value = "/list")
    @RequiresPermissions("account:manage")
    public ResponseEntity<HttpDataResult<PageInfo>> list(
            @RequestParam(required = false, value = "keyword") String keyword,
            @RequestParam(required = false, value = "status") Integer status,
            @RequestParam(required = false, value = "page", defaultValue = "1") Integer page,
            @RequestParam(required = false, value = "pageSize", defaultValue = "10") Integer pageSize,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        HttpDataResult<PageInfo> result = new HttpDataResult<>(request.getRequestURI());
        final TSysAccount currAccount = (TSysAccount) request.getSession().getAttribute(SessionAttributeEnum.CURRENT_ACCOUNT_INFO.getKey());


        PageHelper.startPage(page, pageSize);
        PageInfo pageInfo = new PageInfo(accountService.selectDynamicSqlByParameter(currAccount.getAccountId(), keyword, status));

        List<TSysAccount> accountList = pageInfo.getList();
        List<TSysAccountVO> accountVOList = new ArrayList<>();
        for (TSysAccount account : accountList) {
            TSysAccountVO accountVO = new TSysAccountVO();
            BeanUtils.copyProperties(account, accountVO);
            //设置岗位信息
            if (null != account.getPostTypeId()) {
                TSysDict postType = dictService.selectByPrimaryKey(account.getPostTypeId());
                if (null != postType) {
                    accountVO.setPostTypeName(postType.getDictName());
                }
            }
            //设置角色名称
            List<TSysRole> roleList = roleService.selectRoleByAccountId(account.getAccountId());
            if (null != roleList && !roleList.isEmpty()) {
                accountVO.setRoleName(roleList.stream().map(TSysRole::getRoleName).collect(Collectors.joining("、")));
            }
            //设置账户扩展信息
            TMiAccountExtend accountExtend = accountExtendService.selectByPrimaryKey(account.getAccountId());
            if (accountExtend != null) {
                accountVO.setAccountLevel(accountExtend.getAccountLevel());
                accountVO.setAreasCode(accountExtend.getAreasCode());
                accountVO.setRegionCode(accountExtend.getRegionCode());
                accountVO.setAgentTarget(accountExtend.getAgentTarget());
                accountVO.setAgentL2Target(accountExtend.getAgentL2Target());
                accountVO.setAgentL3Target(accountExtend.getAgentL3Target());
                accountVO.setHospitalTarget(accountExtend.getHospitalTarget());
                accountVO.setHospitalL2Target(accountExtend.getHospitalL2Target());
                accountVO.setHospitalL3Target(accountExtend.getHospitalL3Target());
                //设置所属省份名称
                if (accountExtend.getAreasCode() != null) {
                    TSysAreas areas = areasService.selectByPrimaryKey(accountExtend.getAreasCode());
                    if (areas != null) {
                        accountVO.setAreasCodeName(areas.getName());
                    }
                }
                //设置所属区域名称
                if (accountExtend.getRegionCode() != null) {
                    TMiRegion region = regionService.selectByPrimaryKey(accountExtend.getRegionCode());
                    if (region != null) {
                        accountVO.setRegionCodeName(region.getRegionName());
                    }
                }
                //设置用户等级名称
                TSysDict dict = dictService.selectByPrimaryKey(accountExtend.getAccountLevel());
                if (dict != null) {
                    accountVO.setAccountLevelName(dict.getDictName());
                }
            }
            //设置状态名称
            accountVO.setStatusName(CommonStatusEnum.getDesc(account.getStatus()));

            accountVOList.add(accountVO);
        }

        pageInfo.setList(accountVOList);

        result.setData(pageInfo);

        result.setMessage("获取账户列表成功.");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /***
     *  删除账户
     * @param accountIds
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.DELETE, detail = "删除账户")
    @ApiOperation(value = "删除账户", notes = "删除账户")
    @ApiImplicitParam(dataType = "String[]", allowMultiple = true, name = "accountIds", value = "账户ID数组 示例[1,2,3,4]", required = true)
    @DeleteMapping(value = "/delete/{accountIds}")
    @RequiresPermissions("account:manage:delete")
    public ResponseEntity<HttpDataResult<Boolean>> delete(
            @PathVariable("accountIds") String[] accountIds,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<Boolean> result = new HttpDataResult<>(request.getRequestURI());


        if (null == accountIds || accountIds.length == 0) {
            throw new CheckException("需要删除的账户ID异常，删除操作失败！");
        }

        List<String> accountIdList = new ArrayList<>(Arrays.asList(accountIds));

        TSysAccountExample accountExample = new TSysAccountExample();
        accountExample.createCriteria().andAccountIdIn(accountIdList).andIsDefaultEqualTo(true);

        List<TSysAccount> accountList = accountService.selectByExample(accountExample);
        if (null != accountList && !accountList.isEmpty()) {
            StringBuilder accounts = new StringBuilder();
            for (TSysAccount account : accountList) {
                if (accounts.length() > 0) {
                    accounts.append(",");
                }
                accounts.append(account.getAccount());
            }
            throw new CheckException(String.format("选择账号中[%s]为默认账号，删除操作失败！", accounts.toString()));
        }

        accountExample = new TSysAccountExample();
        accountExample.createCriteria().andAccountIdIn(accountIdList).andIsDefaultEqualTo(false);


        TSysAccount account = new TSysAccount();
        account.setStatus(CommonStatusEnum.DELETE.getCode());


        //删除账户操作 ,将账户状态更新为 删除 -1 状态
        accountService.updateByExampleSelective(account, accountExample);

        result.setData(true);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /***
     *  重置密码
     * @param accountIds
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.UPDATE, detail = "重置密码")
    @ApiOperation(value = "重置密码", notes = "重置密码")
    @ApiImplicitParam(dataType = "String[]", allowMultiple = true, name = "accountIds", value = "账户ID数组 示例[1,2,3,4]", required = true)
    @PutMapping(value = "/resetPwd")
    @RequiresPermissions("account:manage:reset:password")
    public ResponseEntity<HttpDataResult<List<Map<String, String>>>> resetPwd(
            @RequestParam("accountIds") String[] accountIds,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<List<Map<String, String>>> result = new HttpDataResult<>(request.getRequestURI());

        if (null == accountIds || accountIds.length == 0) {
            throw new CheckException("需要重置密码的账户ID异常，无法删除！");
        }
        List<Map<String, String>> resultData = new ArrayList<>();
        for (String accountId : accountIds) {
            TSysAccount account = accountService.selectByPrimaryKey(accountId);

            String newPwd;
            if (null != account.getTel()) {
                newPwd = account.getAccount() + "_" + account.getTel().substring(account.getTel().length() - 4);
            } else {
                newPwd = account.getAccount() + "_" + CommonUtils.randomNumber(4);
            }
            account.setPassword(PwdHashSaltUtils.primitiveSha256Hex(account.getAccount(), newPwd));
            accountService.updateByPrimaryKey(account);

            Map<String, String> dataMap = new HashMap<>();
            dataMap.put("account", account.getAccount());
            dataMap.put("realName", account.getRealName());
            dataMap.put("password", newPwd);
            resultData.add(dataMap);

        }

        result.setData(resultData);
        result.setMessage("重置密码成功！");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /***
     * 岗位类型列表
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "岗位类型列表")
    @ApiOperation(value = "岗位类型列表", notes = "岗位类型列表")
    @GetMapping(value = "/postTypeList")
    public ResponseEntity<HttpDataResult<List<TSysDict>>> postTypeList(
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<List<TSysDict>> result = new HttpDataResult<>(request.getRequestURI());

        List<TSysDict> postTypeList = dictService.selectByDictTypeId(DictTypeEnum.POST_TYPE_GROUP.getId());

        result.setData(postTypeList);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /***
     * 获取用户级别列表
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "获取用户级别列表")
    @ApiOperation(value = "获取用户级别列表", notes = "获取用户级别列表")
    @GetMapping(value = "/accountLevelTypeList")
    public ResponseEntity<HttpDataResult<List<TSysDict>>> accountLevelTypeList(
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<List<TSysDict>> result = new HttpDataResult<>(request.getRequestURI());

        List<TSysDict> accountLevelTypeList = dictService.selectByDictTypeId(DictTypeEnum.ACCOUNT_LEVEL_TYPE_GROUP.getId());

        result.setData(accountLevelTypeList);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /***
     * 获取角色列表
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "获取角色列表")
    @ApiOperation(value = "获取角色列表", notes = "获取角色列表")
    @GetMapping(value = "/roleList")
    public ResponseEntity<HttpDataResult<List<TSysRole>>> roleList(
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<List<TSysRole>> result = new HttpDataResult<>(request.getRequestURI());

        TSysRoleExample roleExample = new TSysRoleExample();
        TSysRoleExample.Criteria criteria = roleExample.createCriteria();
        criteria.andStatusGreaterThan(CommonStatusEnum.DISABLE.getCode());
        roleExample.setOrderByClause("create_time desc");

        List<TSysRole> roleList = roleService.selectByExample(roleExample);

        result.setData(roleList);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /***
     * 获取角色权限列表
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "获取角色权限列表")
    @ApiOperation(value = "获取角色权限列表", notes = "获取角色权限列表")
    @ApiImplicitParam(dataType = "String[]", allowMultiple = true, name = "roleIds", value = "角色ID数组 示例[1,2,3,4]", required = true)
    @GetMapping(value = "/roleAuthList")
    public ResponseEntity<HttpDataResult<List<AuthTreeVO>>> roleAuthList(
            @RequestParam("roleIds") String[] roleIds,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<List<AuthTreeVO>> result = new HttpDataResult<>(request.getRequestURI());

        //树所有列表
        List<TSysAuthority> authorityList = roleAuthorityMapperService.selectAuthorityByRoleIds(Arrays.asList(roleIds));
        List<AuthTreeVO> authTreeVOList = AuthUtils.treeBuilder(authorityList);

        result.setData(authTreeVOList);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /**
     * 新增账户保存提交
     *
     * @param accountDO
     * @param bindingResult
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.INSERT, detail = "新增账户保存提交")
    @ApiOperation(value = "新增账户保存提交", notes = "新增账户保存提交")
    @ApiParam(type = "TSysAccountDO", name = "accountDO", value = "账户新增映射对象", required = true)
    @PostMapping(value = "/addSubmit")
    @RequiresPermissions("account:manage:add")
    public ResponseEntity<HttpDataResult<String>> addSubmit(
            @RequestBody @Validated TSysAccountDO accountDO, BindingResult bindingResult,
            HttpServletRequest request, HttpServletResponse response) throws Exception {

        if (bindingResult.hasErrors()) {
            throw new CheckException(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }

        if (!accountService.verifyAccount(null, accountDO.getAccount())) {
            throw new CheckException("账号重复，无法新增保存提交！");
        }


        HttpDataResult<String> result = new HttpDataResult<>(request.getRequestURI());

        TSysAccount account = new TSysAccount();
        BeanUtils.copyProperties(accountDO, account);
        account.setIsDefault(false);
        String accountId = CommonUtils.randomUUID();
        account.setAccountId(accountId);
        account.setCreateTime(LocalDateTime.now());
        String newPwd;
        if (null != account.getTel()) {
            newPwd = account.getAccount() + "_" + account.getTel().substring(account.getTel().length() - 4);
        } else {
            newPwd = account.getAccount() + "_" + CommonUtils.randomNumber(4);
        }
        account.setPassword(PwdHashSaltUtils.primitiveSha256Hex(account.getAccount(), newPwd));
        account.setSex("1");
        accountService.insertSelective(account);


        //更新维护账户-角色映射
        accountDO.getRoleIdList().forEach(roleId -> {
            TSysAccountRoleMapper accountRoleMapper = new TSysAccountRoleMapper();
            accountRoleMapper.setAccountId(account.getAccountId());
            accountRoleMapper.setRoleId(roleId);
            accountRoleMapperService.insert(accountRoleMapper);
        });

        //更新维护账户扩展表信息
        TMiAccountExtend accountExtend = new TMiAccountExtend();
        BeanUtils.copyProperties(accountDO, accountExtend);
        accountExtend.setAccountId(accountId);

        accountExtendService.insertSelective(accountExtend);

        result.setData(account.getAccountId());
        result.setMessage("新增账户成功，默认密码:[" + newPwd + "]!");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    /***
     * 验证账号唯一性
     * @param accountId
     * @param account
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.CHECK, detail = "验证账号唯一性", isSaveRequestData = true)
    @ApiOperation(value = "验证账号唯一性", notes = "验证账号唯一性")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "String", name = "accountId", value = "账户ID", required = false),
            @ApiImplicitParam(dataType = "String", name = "account", value = "账号", required = true)
    })
    @GetMapping(value = "/verifyAccount")
    public ResponseEntity<HttpDataResult<Boolean>> verifyAccount(
            @RequestParam(required = false, value = "accountId") String accountId,
            @RequestParam(value = "account") String account,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<Boolean> result = new HttpDataResult<>(request.getRequestURI());

        result.setData(accountService.verifyAccount(accountId, account));

        result.setMessage("验证账号唯一性成功.");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);

    }


    /***
     * 账户详情 （修改页获取数据）
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.QUERY, detail = "账户详情 （修改页获取数据）")
    @ApiOperation(value = "账户详情 （修改页获取数据）", notes = "账户详情 （修改页获取数据）")
    @ApiImplicitParam(dataType = "String", name = "accountId", value = "账户ID", required = true)
    @GetMapping(value = "/detail")
    public ResponseEntity<HttpDataResult<Map<String, Object>>> detail(
            @RequestParam(value = "accountId") String accountId,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<Map<String, Object>> result = new HttpDataResult<>(request.getRequestURI());

        Map<String, Object> resultData = new HashMap<>(16);

        TSysAccount account = accountService.selectByPrimaryKey(accountId);
        resultData.put("account", account);

        //账号包含角色列表
        TSysAccountRoleMapperExample accountRoleMapperExample = new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(accountId);
        List<TSysAccountRoleMapper> accountRoleMapperList = accountRoleMapperService.selectByExample(accountRoleMapperExample);
        List<String> roleIdSelectedList = accountRoleMapperList.stream().map(TSysAccountRoleMapper::getRoleId).collect(Collectors.toList());
        resultData.put("roleIdSelectedList", roleIdSelectedList);

        //角色列表
        TSysRoleExample roleExample = new TSysRoleExample();
        TSysRoleExample.Criteria criteria = roleExample.createCriteria();
        criteria.andStatusGreaterThan(CommonStatusEnum.DISABLE.getCode());
        roleExample.setOrderByClause("create_time desc");

        List<TSysRole> roleList = roleService.selectByExample(roleExample);
        resultData.put("roleList", roleList);

        //角色权限树列表
        List<TSysAuthority> authorityList = roleAuthorityMapperService.selectAuthorityByRoleIds(roleIdSelectedList);
        resultData.put("authTreeList", AuthUtils.treeBuilder(authorityList));

        //设置扩展信息内容
        TMiAccountExtend accountExtend = accountExtendService.selectByPrimaryKey(accountId);
        resultData.put("accountExtend", accountExtend);

        result.setData(resultData);
        result.setMessage("OK");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }


    /**
     * 修改账户保存提交
     *
     * @param accountDO
     * @param bindingResult
     * @param request
     * @param response
     * @return
     */
    @OperLog(module = MODULE, action = OperLogActionEnum.UPDATE, detail = "修改账户保存提交")
    @ApiOperation(value = "修改账户保存提交", notes = "修改账户保存提交")
    @ApiParam(type = "TSysAccountDO", name = "accountDO", value = "账户修改映射对象", required = true)
    @PutMapping(value = "/modifySubmit")
    @RequiresPermissions("account:manage:modify")
    public ResponseEntity<HttpDataResult<String>> modifySubmit(
            @RequestBody @Validated TSysAccountDO accountDO, BindingResult bindingResult,
            HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpDataResult<String> result = new HttpDataResult<>(request.getRequestURI());

        if (bindingResult.hasErrors()) {
            throw new CheckException(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
        }
        TSysAccount account = accountService.selectByPrimaryKey(accountDO.getAccountId());

        if (null == account) {
            throw new CheckException("账户ID无效，请检查！");
        }

        if (!accountService.verifyAccount(accountDO.getAccountId(), accountDO.getAccount())) {
            throw new CheckException("账号重复，无法修改保存提交！");
        }

        account.setStatus(accountDO.getStatus());
        account.setRealName(accountDO.getRealName());

        account.setTel(accountDO.getTel());
        account.setEmail(accountDO.getEmail());

        account.setPostTypeId(accountDO.getPostTypeId());
        account.setMemo(accountDO.getMemo());
        account.setExpireTime(accountDO.getExpireTime());

        accountService.updateByPrimaryKey(account);

        //更新维护账户-角色映射
        //删除
        TSysAccountRoleMapperExample accountRoleMapperExample = new TSysAccountRoleMapperExample();
        accountRoleMapperExample.createCriteria().andAccountIdEqualTo(account.getAccountId());
        accountRoleMapperService.deleteByExample(accountRoleMapperExample);
        //添加
        accountDO.getRoleIdList().forEach(roleId -> {
            TSysAccountRoleMapper accountRoleMapper = new TSysAccountRoleMapper();
            accountRoleMapper.setAccountId(account.getAccountId());
            accountRoleMapper.setRoleId(roleId);
            accountRoleMapperService.insert(accountRoleMapper);
        });

        //更新维护账户扩展信息
        TMiAccountExtend accountExtend = accountExtendService.selectByPrimaryKey(accountDO.getAccountId());
        if (accountExtend != null) {
            accountExtend.setAccountLevel(accountDO.getAccountLevel());
            accountExtend.setAreasCode(accountDO.getAreasCode());
            accountExtend.setRegionCode(accountDO.getRegionCode());
            accountExtend.setAgentTarget(accountDO.getAgentTarget());
            accountExtend.setAgentL2Target(accountDO.getAgentL2Target());
            accountExtend.setAgentL3Target(accountDO.getAgentL3Target());
            accountExtend.setHospitalTarget(accountDO.getHospitalTarget());
            accountExtend.setHospitalL2Target(accountDO.getHospitalL2Target());
            accountExtend.setHospitalL3Target(accountDO.getHospitalL3Target());

            accountExtendService.updateByPrimaryKey(accountExtend);
        }

        result.setMessage("修改账户信息成功!");
        result.setStatus(HttpStatus.OK.value());
        return new ResponseEntity<>(result, HttpStatus.OK);
    }
}
